using System;
using System.Collections.Generic;
using System.ComponentModel;
using RollManager.Library;
using RollManager.Library.ActionSteps;
using RollManager.Library.Utils;

namespace RollManager.Utils
{
    public class ActionWorker : BackgroundWorker
    {
        private readonly DevLevel m_devLevel;
        private readonly SubAction m_subAction;
        private readonly ProgressReporter m_progress;
        private List<string> m_servers;
        private bool m_simulation;
        private Dictionary<string,string> m_context = new Dictionary<string, string>();

        public Dictionary<string,string> Context
        {
            get { return m_context; }
        }

        public ActionWorker( DevLevel devLevel, SubAction subAction, bool simulation )
        {
            // save instance fields
            m_devLevel = devLevel;
            m_subAction = subAction;
            m_simulation = simulation;
            getServers();

            // setup background worker params
            DoWork += runCommand;
            WorkerReportsProgress = true;
            WorkerSupportsCancellation = true;

            m_progress = new ProgressReporter( this );
        }

        private void getServers()
        {
            m_servers = new List<string>();
            foreach( Server server in Database.GetServers( m_subAction.ServerGroupId ) )
            {
                m_servers.Add( server.Name );
            }
        }

        private void runCommand( object sender, DoWorkEventArgs e )
        {
            // Run each step for each server
            for( int i=0; i< m_servers.Count; i++ )
            {
                m_progress.Add( new ServerAdvancement( m_servers[ i ] ) );

                for( int stepIdx = 0 ; stepIdx < m_subAction.StepList.Count ; stepIdx++ )
                {
                    ActionStep step = m_subAction.StepList[ stepIdx ];
                    try
                    {
                        Object retValue = step.RunStep( m_progress, i, m_servers, m_simulation, m_context );
                        if( retValue is List<string> )
                        {
                            m_servers = (List<string>) retValue;
                            m_subAction.StepList.RemoveAt( stepIdx );

                            runCommand( sender, e );
                            return;
                        }
                    }
                    catch( Exception ex )
                    {
                        // log problem
                        m_progress.Add( ex );

                        // log question to user
                        string msg =
                            string.Format( "Problem in step {0}: {1}  Do you wish to abort?", step.Name, ex.Message );

                        // ask user to abort
                        if( Common.ConfirmAction( msg, "Problem Occurred" ) )
                        {
                            m_progress.Add( msg + "  User Aborted" );
                            e.Cancel = true;
                            return;
                        }
                        else
                        {
                            m_progress.Add( msg + "  Moving on to next step." );
                        }
                    }

                    if( CancellationPending )
                    {
                        e.Cancel = true;
                        return;
                    }
                }
            }
        }
    }
}